package com.dqx.opengl_es_demo.model.utils;

import android.content.res.Resources;
import android.opengl.GLES20;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;

/**
 * 加载着色器的工具类
 */
public class ShaderUtil {
    /**
     * 加载着色器
     *
     * @param shaderType 着色器类型：
     *                   GLES20.GL_VERTEX_SHADER（顶点着色器）
     *                   GLES20.GL_FRAGMENT_SHADER（片元着色器）
     * @param source     着色器的代码脚本
     * @return
     */
    public static int loadShader(int shaderType, String source) {
        //创建着色器对象
        int shader = GLES20.glCreateShader(shaderType);
        if (shader != 0) {//着色器创建成功
            //加载着色器的源代码
            GLES20.glShaderSource(shader, source);
            //编译着色器
            GLES20.glCompileShader(shader);
            //存放编译状态的数组
            int[] compiled = new int[1];
            //获取着色器的编译状态
            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
            if (compiled[0] == 0) {//编译失败
                //显示错误日志
                Log.e("ES20_ERROR", GLES20.glGetShaderInfoLog(shader));
                //删除此着色器
                GLES20.glDeleteShader(shader);
                shader = 0;
            }
        }
        return shader;
    }

    /**
     * 创建着色器程序
     *
     * @param vertexSource   顶点着色器的脚本代码
     * @param fragmentSource 片元着色器的脚本带密码
     * @return
     */
    public static int createProgram(String vertexSource, String fragmentSource) {
        //加载顶点着色器
        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
        if (vertexShader == 0)//加载失败
            return 0;

        //加载片元着色器
        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
        if (pixelShader == 0)//加载失败
            return 0;

        //创建程序
        int program = GLES20.glCreateProgram();
        if (program != 0) {//创建成功
            //向程序中加入顶点着色器
            GLES20.glAttachShader(program, vertexShader);
            checkGlError("glAttachShader");
            //向程序中加入片元着色器
            GLES20.glAttachShader(program, pixelShader);
            checkGlError("glAttachShader");
            //链接程序
            GLES20.glLinkProgram(program);
            //存放链接状态的数组
            int[] linkStatus = new int[1];
            //获取程序的链接状态
            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
            if (linkStatus[0] != GLES20.GL_TRUE) {//链接失败
                //输出错误日志
                Log.e("ES20_ERROR", GLES20.glGetProgramInfoLog(program));
                //删除此程序
                GLES20.glDeleteProgram(program);
                program = 0;
            }
        }
        return program;
    }

    /**
     * 检查每一步操作是否有错误的方法
     *
     * @param op
     */
    public static void checkGlError(String op) {
        int error;
        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            Log.e("ES20_ERROR", op + ": glError " + error);
            throw new RuntimeException(op + ": glError " + error);
        }
    }

    /**
     * 从assets目录下的sh文件中加载着色器脚本代码
     *
     * @param fname
     * @param r
     * @return
     */
    public static String loadFromAssetsFile(String fname, Resources r) {
        String result = null;
        try {
            InputStream in = r.getAssets().open(fname);
            int ch = 0;
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            while ((ch = in.read()) != -1) {
                baos.write(ch);
            }
            byte[] buff = baos.toByteArray();
            baos.close();
            in.close();
            result = new String(buff, "UTF-8");
            result = result.replaceAll("\\r\\n", "\n");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}
